package icraf.carbon.gui;

import icraf.carbon.core.CostBenefitUnit;
import icraf.carbon.core.OpcostData;
import icraf.carbon.core.Project;
import icraf.carbon.core.Summary;
import icraf.carbon.gui.MenuFactory.MenuProperty;
import icraf.common.gui.MenuGenerator;
import icraf.common.gui.MenuGenerator.IconModel;

import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.DecimalFormat;
import java.text.ParseException;
import java.util.ArrayList;

import javax.swing.DefaultComboBoxModel;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.JTable;
import javax.swing.ListModel;

public class SummaryPanel extends JPanel {

	class EmissionPanel extends JPanel {
		private static final long serialVersionUID = -7686958983870618206L;
		private JLabel emitLabel;
		private boolean isAreaScale = false;
		private OpcostTableModel model;
		private JComboBox<String> unitCB = new JComboBox<String>();
		private DefaultComboBoxModel<String> unitModelCB = new DefaultComboBoxModel<String>();

		public EmissionPanel() {
			this.setLayout(new BorderLayout());
			model = new OpcostTableModel();
			MatrixPanel mp = new MatrixPanel(model);
			mp.getTable().setAutoResizeMode(JTable.AUTO_RESIZE_SUBSEQUENT_COLUMNS);
			this.add(mp);

			JLabel l = new JLabel("Total "
					+ MenuProperty.PROJECT_AVOIDED_EMISSION.getLabel() + ":");
			emitLabel = new JLabel();

			unitModelCB.addElement(MenuProperty.UNIT_EMISSION_HA.getLabel());
			unitModelCB.addElement(MenuProperty.UNIT_EMISSION.getLabel());
			unitCB.setModel(unitModelCB);
			unitCB.addActionListener(new ActionListener() {

				@Override
				public void actionPerformed(ActionEvent e) {
					setAreaScale(unitCB.getSelectedIndex() == 1);
				}
			});

			JPanel p = new JPanel(new FlowLayout(FlowLayout.LEFT, 10, 5));
			p.add(l);
			p.add(emitLabel);
			p.add(unitCB);
			this.add(p, BorderLayout.NORTH);
		}

		public boolean isAreaScale() {
			return isAreaScale;
		}

		public void setAreaScale(boolean isAreaScale) {
			this.isAreaScale = isAreaScale;
			model.setAreaScale(isAreaScale);
			double d = model.getTotalEmission();
			emitLabel.setText(formatter.format(d));
		}

		public void setProject(Project project,
				CostBenefitUnit costBenefitUnit, double threshold, boolean isEligibleOnly) {
			model.setProject(project, costBenefitUnit, threshold, isEligibleOnly);
			double d = model.getTotalEmission();
			emitLabel.setText(formatter.format(d));
		}

		
	}

	public class Listener implements ActionListener {

		@Override
		public void actionPerformed(ActionEvent e) {
			if (MenuProperty.EDIT_UPDATE.isAction(e)) {
				String inp = JOptionPane.showInputDialog(
						MenuProperty.PROJECT_SUMMARY_THRESHOLD.getLabel(),
						formatter.format(threshold));
				if (inp != null) {
					try {
						double d = formatter.parse(inp.trim()).doubleValue();
						threshold = d;
						updateOpcostPanel();
					} catch (ParseException e1) {

					}
					thresholdLabel.setText(formatter.format(threshold));
				}
			} else if(e.getSource().equals(isEligibleOnlyCB)) {
				updateOpcostPanel();
			}

		}

	}

	public class OpcostTableModel extends MatrixTableModel {
		private static final long serialVersionUID = 8968868974903218229L;
		private CostBenefitUnit costBenefitUnit;
		private String header[] = { 
				MenuProperty.PROJECT_ZONE.getLabel(),
				MenuProperty.PROJECT_LU_FROM.getLabel(),
				MenuProperty.PROJECT_LU_INTO.getLabel(),
				MenuProperty.PROJECT_EMISSION.getLabel(),
				MenuProperty.PROJECT_OPCOST.getLabel(), 
				MenuProperty.PROJECT_ZONE_ELIGIBILITY.getLabel()};
		
		private boolean isAreaScale = false;
		private ArrayList<OpcostData> opcostArr;
		private Project project;
		private NumberRowHeader tableListModel = new NumberRowHeader(this);
		private double threshold;
		private boolean isEligibleOnly = false;

		@Override
		public Class<?> getColumnClass(int column) {
			return getValueAt(0, column).getClass();
		}

		@Override
		public int getColumnCount() {
			return header.length;
		}

		@Override
		public String getColumnName(int col) {
			return header[col];
		}

		public CostBenefitUnit getCostBenefitUnit() {
			return costBenefitUnit;
		}

		public Project getProject() {
			return project;
		}

		@Override
		public int getRowCount() {
			if (opcostArr == null) {
				return 0;
			}
			return opcostArr.size();
		}

		@Override
		public ListModel<Object> getRowHeaderModel() {
			return tableListModel;
		}

		public double getThreshold() {
			return threshold;
		}

		public double getTotalEmission() {
			double d = 0;
			for (int r = 0; r < getRowCount(); r++) {
				d += (Double) getValueAt(r, 3);
			}
			return d;
		}

		@Override
		public Object getValueAt(int row, int column) {
			if (opcostArr == null) {
				return null;
			}
			OpcostData d = opcostArr.get(row);
			switch (column) {
			case 0:
				return d.getZone().getLabel();
			case 1:
				return d.getLandCover1().getLabel();
			case 2:
				return d.getLandCover2().getLabel();
			case 3:
				return d.getEmission()
						* (isAreaScale ? project.getTotalArea() : 1);
			case 4:
				return d.getCost(costBenefitUnit);
			case 5:
				return d.isEligible();
			}
			return null;
		}

		public boolean isAreaScale() {
			return isAreaScale;
		}

		@Override
		public boolean isCellEditable(int row, int col) {
			return false;
		}

		public void setAreaScale(boolean isAreaScale) {
			this.isAreaScale = isAreaScale;
			fireTableDataChanged();
		}

		public void setProject(Project project,
				CostBenefitUnit costBenefitUnit, double threshold, boolean isEligibleOnly) {
			this.project = project;
			this.costBenefitUnit = costBenefitUnit;
			this.isEligibleOnly  = isEligibleOnly;
			setThreshold(threshold);
		}

		public void setThreshold(double threshold) {
			if (project == null || costBenefitUnit == null) {
				opcostArr = null;
				return;
			}
			this.threshold = threshold;
			opcostArr = project.getAvoidedEmissionList(threshold,
					costBenefitUnit, isEligibleOnly);
			fireTableStructureChanged();
		}

	}

	public class SummaryTableModel extends MatrixTableModel {
		private static final long serialVersionUID = 8968868974903218229L;
		private String header[] = { 
				MenuProperty.PROJECT_FIELDS.getLabel(), 
				MenuProperty.PROJECT_VALUE.getLabel()};
		private Summary summary;
		private NumberRowHeader tableListModel = new NumberRowHeader(this);

		@Override
		public Class<?> getColumnClass(int column) {
			if (column == 0)
				return String.class;
			return Double.class;
		}

		@Override
		public int getColumnCount() {
			return header.length;
		}

		@Override
		public String getColumnName(int col) {
			return header[col];
		}


		@Override
		public int getRowCount() {
			return Summary.summaryItems.length;//+Summary.summaryCBUItems.length*cbuList.length;
		}

		@Override
		public ListModel<Object> getRowHeaderModel() {
			return tableListModel;
		}

		public Summary getSummary() {
			return summary;
		}

		@Override
		public Object getValueAt(int row, int column) {
				if (column == 0) {
					return Summary.summaryItems[row].getLabel();
				}
				return Summary.getSummaryValue(Summary.summaryItems[row], summary, null);
			
		}

		@Override
		public boolean isCellEditable(int row, int col) {
			return false;
		}

		public void setSummary(Summary summary) {
			this.summary = summary;
			fireTableDataChanged();
			tableListModel.fireContentChange(getColumnCount());
		}

	}

	private static final long serialVersionUID = 1479385883027653429L;
	private DecimalFormat formatter = new DecimalFormat();

	private ActionListener listener = new Listener();

	private JPanel opcostPanel;

	private JTabbedPane opcostTablePanel;
	private JTabbedPane listLUTablePanel;

	private Project project;

	private MatrixPanel summaryPanel;
	private SummaryTableModel summaryTableModel = new SummaryTableModel();
	private JTabbedPane tabPanel;

	private double threshold = 5;
	private JLabel thresholdLabel;
	private JButton updateButton;
	private JCheckBox isEligibleOnlyCB = new JCheckBox(MenuProperty.PROJECT_ELIG_ONLY.getLabel());
	private JPanel listLUPanel;

	public SummaryPanel() {
		summaryPanel = new MatrixPanel(summaryTableModel);
		summaryPanel.getTable().setAutoResizeMode(JTable.AUTO_RESIZE_SUBSEQUENT_COLUMNS);
		
		JLabel tLabel = new JLabel(
				MenuProperty.PROJECT_SUMMARY_THRESHOLD.getLabel() + ":");
		thresholdLabel = new JLabel(formatter.format(threshold));
		updateButton = MenuGenerator.createButton(MenuProperty.EDIT_UPDATE,
				listener, true, IconModel.ICON16);
		isEligibleOnlyCB.addActionListener(listener);
		JPanel tPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 10, 0));
		tPanel.add(tLabel);
		tPanel.add(thresholdLabel);
		tPanel.add(updateButton);
		tPanel.add(isEligibleOnlyCB);
		opcostPanel = new JPanel(new BorderLayout());
		opcostPanel.add(tPanel, BorderLayout.NORTH);
		listLUPanel = new JPanel(new BorderLayout());
		

		tabPanel = new JTabbedPane();
		tabPanel.addTab(MenuProperty.PROJECT_SUMMARY.getLabel(), summaryPanel);
		tabPanel.addTab(MenuProperty.PROJECT_AVOIDED_EMISSION.getLabel(),
				opcostPanel);
		tabPanel.addTab(MenuProperty.PROJECT_OPCOST.getLabel(),
				listLUPanel);
		this.setLayout(new BorderLayout());
		this.add(tabPanel);
	}

	public Project getProject() {
		return project;
	}

	public void setProject(Project project) {
		this.project = project;
		project.updateDataArray();
		summaryTableModel.setSummary(project.getSummary());
		summaryPanel.getTable().getColumnModel().getColumn(0)
				.setPreferredWidth(300);
		updateOpcostPanel();
		updateListLUPanel();
	}

	private void updateOpcostPanel() {
		if (opcostTablePanel == null) {
			opcostTablePanel = new JTabbedPane();
			opcostPanel.add(opcostTablePanel);
		}
		if (project == null)
			return;

		ArrayList<CostBenefitUnit> cbList = project.getCostBenefitUnitList();
		if (cbList == null)
			return;

		while (opcostTablePanel.getTabCount() > cbList.size()) {
			opcostTablePanel.remove(0);
		}
		for (int i = 0; i < cbList.size(); i++) {
			CostBenefitUnit cb = cbList.get(i);
			EmissionPanel ep;
			if (opcostTablePanel.getTabCount() < cbList.size()) {
				ep = new EmissionPanel();
				ep.setProject(project, cb, threshold, isEligibleOnlyCB.isSelected());
				opcostTablePanel.addTab(cb.getLabel(), ep);
			} else {
				ep = (EmissionPanel) opcostTablePanel.getComponentAt(i);
				opcostTablePanel.setTitleAt(i, cb.getLabel());
			}
			ep.setProject(project, cb, threshold, isEligibleOnlyCB.isSelected());
		}

	}
	
	private void updateListLUPanel() {
		if (listLUTablePanel == null) {
			listLUTablePanel = new JTabbedPane();
			listLUPanel.add(listLUTablePanel);
		}
		if (project == null)
			return;

		ArrayList<CostBenefitUnit> cbList = project.getCostBenefitUnitList();
		if (cbList == null)
			return;

		while (listLUTablePanel.getTabCount() > cbList.size()) {
			listLUTablePanel.remove(0);
		}
		for (int i = 0; i < cbList.size(); i++) {
			CostBenefitUnit cb = cbList.get(i);
			OutputEmissionNPVPanel ep;
			if (listLUTablePanel.getTabCount() < cbList.size()) {
				ep = new OutputEmissionNPVPanel();
				listLUTablePanel.addTab(cb.getLabel(), ep);
			} else {
				ep = (OutputEmissionNPVPanel) listLUTablePanel.getComponentAt(i);
				listLUTablePanel.setTitleAt(i, cb.getLabel());
			}
			ep.setProject(project, cb);

		}

	}


}
